package com.eight.cloud.excel.validated;

import cn.idev.excel.annotation.ExcelProperty;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.SneakyThrows;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Excel数据校验（核心校验逻辑）
 *
 * @ClassName: EasyExcelValidHelper
 * @Author: TXC
 * @Date: 2025-08-08 11:02
 **/
public class FastExcelValidHelper {
    /**
     * JSR303校验器实例
     */
    private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    /**
     * 字段注解缓存（Key: 类类型, Value: 字段名与表头映射）
     */
    private static final Cache<Class<?>, Map<String, String>> fieldExcelPropertyCache = CacheBuilder.newBuilder()
            .maximumSize(100) // 最大缓存100个类
            .expireAfterWrite(1, TimeUnit.HOURS)
            .build();

    /**
     * 执行实体校验
     * @param obj 待校验对象
     * @return 错误信息（格式：表头+错误描述）
     */
    public static <T> String validateEntity(T obj) {
        StringBuilder errorMsg = new StringBuilder();
        Set<ConstraintViolation<T>> violations = validator.validate(obj);
        if (violations.isEmpty()) {
            return "解析数据出错";
        }
        Map<String, String> fieldMap = getFieldExcelPropertyMap(obj.getClass());
        violations.forEach(v -> {
            String fieldName = v.getPropertyPath().toString();
            Optional.ofNullable(fieldMap.get(fieldName))
                    .ifPresent(header -> errorMsg.append(header).append(v.getMessage()).append(";"));
        });
        return errorMsg.toString();
    }

    /**
     * 获取类字段与表头映射（带缓存）
     */
    @SneakyThrows
    private static <T> Map<String, String> getFieldExcelPropertyMap(Class<T> clazz) {
        return fieldExcelPropertyCache.get(clazz, () -> {
            Map<String, String> mapping = new HashMap<>();
            for (Field field : clazz.getDeclaredFields()) {
                ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                if (annotation != null && annotation.value().length > 0) {
                    mapping.put(field.getName(), annotation.value()[0]);
                }
            }
            return mapping;
        });
    }
}
